Implementation Notes

Issue #1 — Project Foundation & Core Framework — 2026-06-14

Design Decisions

Decision PipelineStage uses Box<dyn> dynamic dispatch

Ambiguity: Spec said "PipelineStage trait objects" without specifying ownership model.

Choice: Vec<Box<dyn PipelineStage>> — Pipeline owns all stages.

Rationale: No shared ownership needed between pipelines; Box is simpler and avoids Arc ref-count overhead. If shared stages are needed later, the caller can wrap in Arc externally.

Decision RelayStats uses AtomicU64 directly

Ambiguity: Spec listed counter fields but not the concurrency primitive.

Choice: AtomicU64 fields on RelayStats with a snapshot() method returning a plain struct.

Rationale: Zero dependencies, lock-free, sufficient for an embedded library. Callers can wrap with their metrics system (Prometheus, etc.) using the snapshot API.

Deviations

Deviation dhcproto feature mapping removed

Spec said: dhcpv4 = ["dhcproto/v4"], dhcpv6 = ["dhcproto/v6"].

Implemented: dhcpv4 = [], dhcpv6 = [] — no dhcproto sub-features enabled.

Why: dhcproto v0.14 has no v4 or v6 Cargo features — only default and serde. The v4/v6 types are always available in the crate; compile-time gating is handled entirely by our feature flags.

Deviation socket2 resolves to v0.5, v0.6 also present

Spec said: socket2 = "0.5".

Implemented: socket2 v0.5.10 for our direct dependency; tokio pulls v0.6.4 as a transitive dep in test profile. Both compatible.

Why: No action needed — Cargo resolves both versions. Upgrade to 0.6 when tokio stabilizes on it.

Tradeoffs

Tradeoff RelayConfig::validate() vs builder pattern

Alternatives: (A) RelayConfigBuilder with .build() -> Result pattern; (B) plain struct with validate() post-hoc.

Chose B: Simpler API, fewer types. The config is typically deserialized from JSON/YAML and validated once at startup. A builder adds ceremony for no gain in this use case.

Tradeoff Pipeline::execute() returns Result<bool> vs separate halt enum

Alternatives: (A) Result<PipelineOutcome> enum with Forward/Drop variants; (B) Result<bool>.

Chose B: Ok(false) for drop, Ok(true) for continue. The bool is unambiguous per the spec and avoids an extra type. An enum could be introduced later without breaking API changes if needed.

Open Questions

Question Should we upgrade dhcproto to v0.15?

dhcproto v0.15.0 is available (we locked to v0.14.0 per SPEC). The diff may include API changes that affect downstream issues #2–#6. Review before upgrading.

Question Future: re-add dhcproto feature mapping?

If a future dhcproto version adds v4/v6 Cargo features, should we map our features to theirs? This would reduce binary size by excluding unused protocol code. Track dhcproto releases.